package log

import (
	"context"
	"fmt"
	_ "peilian-api/bootstrap"

	"peilian-api/app/global/common"
	"peilian-api/app/global/variable"
	"peilian-api/utils/sdk"
	"time"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type MyLogger struct {
	Zlog *zap.Logger
}

var Logger *MyLogger
var ZapLogger *zap.Logger

func CombineStrings(msg ...string) string {
	s := ""
	for _, v := range msg {
		s = s + v
	}
	return s
}

func (log *MyLogger) Debug(msg ...string) {
	log.Zlog.Debug(CombineStrings(msg...))
}

func (log *MyLogger) DebugF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	log.Zlog.Debug(fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...)))
}

func (log *MyLogger) DebugMsgF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	msgInfo := fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...))
	sdk.SendMsg(msgInfo)
	Logger.Zlog.Debug(msgInfo)
}

func (log *MyLogger) Info(msg ...string) {
	log.Zlog.Info(CombineStrings(msg...))
}

func (log *MyLogger) InfoF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	log.Zlog.Info(fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...)))
}

func (log *MyLogger) InfoMsgF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	msgInfo := fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...))
	sdk.SendMsg(msgInfo)
	Logger.Zlog.Info(msgInfo)
}

func (log *MyLogger) Warn(msg ...string) {
	log.Zlog.Warn(CombineStrings(msg...))
}

func (log *MyLogger) WarnF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	log.Zlog.Warn(fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...)))
}

func (log *MyLogger) WarnMsgF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	msgInfo := fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...))
	sdk.SendMsg(msgInfo)
	Logger.Zlog.Warn(msgInfo)
}

func (log *MyLogger) Error(msg ...string) {
	log.Zlog.Error(CombineStrings(msg...))
}

func (log *MyLogger) ErrorF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	Logger.Zlog.Error(fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...)))
}

func (log *MyLogger) ErrorMsgF(ctx context.Context, msg ...string) {
	trace := GetTraceCtx(ctx).Value(common.TraceKey).(*Trace)
	msgInfo := fmt.Sprintf("trace_id: %s, %s", trace.TraceId, CombineStrings(msg...))
	sdk.SendMsg(msgInfo)
	Logger.Zlog.Error(msgInfo)
}

func StandardTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}

func NewPuFaEncoderConfig() zapcore.EncoderConfig {
	return zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     StandardTimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
}

func InitLogger(logPath string) *zap.Logger {
	if len(logPath) == 0 {
		logPath = variable.Config.Log.File
	}
	encoder := zapcore.NewConsoleEncoder(NewPuFaEncoderConfig())
	lumberJackLogger := &lumberjack.Logger{
		Filename:   logPath,
		MaxSize:    variable.Config.Log.MaxSize,
		MaxBackups: variable.Config.Log.MaxBackups,
		MaxAge:     variable.Config.Log.MaxAge,
		Compress:   variable.Config.Log.Compress,
	}
	writeSyncer := zapcore.AddSync(lumberJackLogger)

	zapCore := zapcore.NewCore(encoder, writeSyncer, zap.DebugLevel)
	return zap.New(zapCore, zap.AddCaller(), zap.AddCallerSkip(1))
}

func init() {
	ZapLogger = InitLogger(variable.Config.Log.File)
	Logger = new(MyLogger)
	Logger.Zlog = ZapLogger
	Logger.Zlog.Debug("init logger")
}
